#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <type_system/schema.hpp>
#include <type_system/schema_parser.hpp>
#include <processing/sql_query_resolver.hpp>
#include <processing/parse_document.hpp>
#include <processing/processing_pipeline.hpp>
#include <processing/render_sql.hpp>
#include <data/sql/postgresql_renderer.hpp>
#include <data/sql/postgresql_data_reader.hpp>
#include <serialization/json/json_serializer.hpp>
#include <serialization/buffer_writer.hpp>
#include <struct/query_context.hpp>
#include <type_system/builtin_types.hpp>

#include <string>

using namespace blitz_query_cpp;

TEST(SqlResolver, SimpleSelect)
{
    std::string scm = R""""(
        schema { query: Query }
        type Query
        {
           Users :[User]
        }
        type User @table(table: "user" schema: "test")
        {
           Id: Int @column(name: "id" IsPK: True)
           Name: String @column(name: "name")
           Age: Int  @column(name: "age")
           AccountId :Int @always_projected
        }

        directive @table(table: String schema: String) on OBJECT
        directive @column(name: String IsPK: Boolean = False) on FIELD_DEFINITION
        )"""";

    std::string query =
        R""""(
        {
            Users {     
                Name
                Age
                Id
            }
        }
        )"""";

    schema_t my_schema;
    EXPECT_EQ(add_introspection_types(my_schema), true);

    schema_parser_t parser;
    bool res = parser.parse(my_schema, scm);
    EXPECT_EQ(res, true);
    EXPECT_EQ(my_schema.query_type_name, "Query");
    std::cout << parser.get_error_msg() << std::endl;

    options_t options{
        {"connection_string", "user=postgres password=Welcome01 host=127.0.0.1 dbname=test"}};

    writer_options_t wtiter_options;
    db_connection_options db_options{};

    query_context context(query, &my_schema, options);

    processing_pipeline<parse_document,
                        sql_query_resolver,
                        render_sql<sql::postgresql_renderer>
                       >
        pipeline;

    pipeline.process(context);
    EXPECT_EQ(context.error_msgs.size(), 0ul);
    EXPECT_EQ(context.data["sql"], "SELECT _a1.name, _a1.age, _a1.id, _a1.\"AccountId\" FROM test.user as _a1");
}



TEST(SqlResolver, SelectWithOffsetPagination)
{
    std::string scm = R""""(
        schema { query: Query }
        type Query
        {
           Users :UserCollectionSegment
        }

        "Information about pagination"
        type CollectionSegmentInfo
        {
            "Indicates whether more items exist following the set defined by the clients arguments."
            hasNextPage: Boolean!
            "Indicates whether more items exist prior the set defined by the clients arguments."
            hasPreviousPage Boolean!
        }
        type UserCollectionSegment @page_segment_info
        {
            pageInfo: CollectionSegmentInfo!
            items:[User]
            totalCount: Int!
        }
        type User @table(table: "user" schema: "test")
        {
           Id: Int @column(name: "id" IsPK: True)
           Name: String @column(name: "name")
           Age: Int  @column(name: "age")
           AccountId :Int @always_projected
        }

        directive @table(table: String schema: String) on OBJECT
        directive @column(name: String IsPK: Boolean = False) on FIELD_DEFINITION
        directive @page_segment_info on OBJECT
        )"""";

    std::string query =
        R""""(
        {
            Users {     
                Name
                Age
                Id
            }
        }
        )"""";

    schema_t my_schema;
    EXPECT_EQ(add_introspection_types(my_schema), true);

    schema_parser_t parser;
    bool res = parser.parse(my_schema, scm);
    EXPECT_EQ(res, true);
    EXPECT_EQ(my_schema.query_type_name, "Query");
    std::cout << parser.get_error_msg() << std::endl;

    options_t options{
        {"connection_string", "user=postgres password=Welcome01 host=127.0.0.1 dbname=test"}};

    writer_options_t wtiter_options;
    db_connection_options db_options{};

    query_context context(query, &my_schema, options);

    processing_pipeline<parse_document,
                        sql_query_resolver,
                        render_sql<sql::postgresql_renderer>
                       >
        pipeline;

    pipeline.process(context);
    EXPECT_EQ(context.error_msgs.size(), 0ul);
    EXPECT_EQ(context.data["sql"], "SELECT _a1.name, _a1.age, _a1.id, _a1.\"AccountId\" FROM test.user as _a1");
}